package com.imut.lagain.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.imut.lagain.entity.AccessLog;
import com.imut.lagain.repository.AccessLogRepository;
import com.imut.lagain.service.IAccessLogService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;

/**
 * 访问日志服务类
 * 提供访问日志的业务逻辑处理
 */
@Service
@RequiredArgsConstructor
@Transactional
public class AccessLogServiceImpl extends ServiceImpl<AccessLogRepository, AccessLog> implements IAccessLogService {
    private static final Logger log = LoggerFactory.getLogger(AccessLogServiceImpl.class);

    
    /**
     * 记录访问日志
     * @param userId 用户ID
     * @param path 访问路径
     * @param method 请求方法
     * @param ipAddress IP地址
     * @param userAgent 用户代理
     * @param referer 来源页面
     * @param statusCode 状态码
     * @param responseTime 响应时间（毫秒）
     * @param requestParams 请求参数
     * @return 创建的访问日志
     */
    public AccessLog logAccess(Long userId, String path, String method, String ipAddress, 
                              String userAgent, String referer, Integer statusCode, 
                              Long responseTime, String requestParams) {
        if (!StringUtils.hasText(path) || !StringUtils.hasText(method)) {
            return null;
        }
        
        AccessLog accessLog = new AccessLog();
         accessLog.setUserId(userId);
         accessLog.setPath(path);
         accessLog.setMethod(method);
         accessLog.setIpAddress(ipAddress);
         accessLog.setUserAgent(userAgent);
         accessLog.setReferer(null);
         accessLog.setStatusCode(statusCode);
         accessLog.setResponseTime(responseTime);
         accessLog.setRequestParams(null); // 请求参数，这里暂时设为null
        accessLog.setAccessTime(LocalDateTime.now());
        accessLog.setCreateTime(LocalDateTime.now());
        
        boolean saved = this.save(accessLog);
        if (saved) {
            log.debug("Logged access: {} {} by user {} from {}", method, path, userId, ipAddress);
            return accessLog;
        } else {
            log.error("Failed to log access: {} {}", method, path);
            return null;
        }
    }
    
    /**
     * 记录访问日志（简化版本）
     * @param userId 用户ID
     * @param path 访问路径
     * @param method 请求方法
     * @param ipAddress IP地址
     * @param userAgent 用户代理
     * @param statusCode 状态码
     * @param responseTime 响应时间（毫秒）
     * @param errorMessage 错误信息
     * @return 创建的访问日志
     */
    public AccessLog logAccess(Long userId, String path, String method, String ipAddress, 
                              String userAgent, int statusCode, long responseTime, String errorMessage) {
        if (!StringUtils.hasText(path) || !StringUtils.hasText(method)) {
            return null;
        }
        
        AccessLog accessLog = new AccessLog();
        accessLog.setUserId(userId);
        accessLog.setPath(path);
        accessLog.setMethod(method);
        accessLog.setIpAddress(ipAddress);
        accessLog.setUserAgent(userAgent);
        accessLog.setReferer(null); // Referer头，这里暂时设为null
        accessLog.setStatusCode(statusCode);
        accessLog.setResponseTime(responseTime);
        accessLog.setRequestParams(errorMessage); // 使用errorMessage作为请求参数
        accessLog.setAccessTime(LocalDateTime.now());
        accessLog.setCreateTime(LocalDateTime.now());
        
        boolean saved = this.save(accessLog);
        if (saved) {
            log.debug("Logged access: {} {} by user {} from {}", method, path, userId, ipAddress);
            return accessLog;
        } else {
            log.error("Failed to log access: {} {}", method, path);
            return null;
        }
    }
    
    /**
     * 根据用户ID分页查询访问日志
     * @param userId 用户ID
     * @param page 分页参数
     * @return 访问日志分页列表
     */
    @Transactional(readOnly = true)
    public IPage<AccessLog> getLogsByUserId(Long userId, Page<AccessLog> page) {
        if (userId == null) {
            return new Page<>();
        }
        return baseMapper.findByUserIdWithPage(userId, page);
    }
    
    /**
     * 根据访问路径分页查询
     * @param path 访问路径
     * @param page 分页参数
     * @return 访问日志分页列表
     */
    @Transactional(readOnly = true)
    public IPage<AccessLog> getLogsByPath(String path, Page<AccessLog> page) {
        if (!StringUtils.hasText(path)) {
            return new Page<>();
        }
        return baseMapper.findByPathWithPage(path, page);
    }
    
    /**
     * 根据请求方法分页查询
     * @param method 请求方法
     * @param page 分页参数
     * @return 访问日志分页列表
     */
    @Transactional(readOnly = true)
    public IPage<AccessLog> getLogsByMethod(String method, Page<AccessLog> page) {
        if (!StringUtils.hasText(method)) {
            return new Page<>();
        }
        return baseMapper.findByMethodWithPage(method, page);
    }
    
    /**
     * 根据IP地址分页查询
     * @param ipAddress IP地址
     * @param page 分页参数
     * @return 访问日志分页列表
     */
    @Transactional(readOnly = true)
    public IPage<AccessLog> getLogsByIpAddress(String ipAddress, Page<AccessLog> page) {
        if (!StringUtils.hasText(ipAddress)) {
            return new Page<>();
        }
        return baseMapper.findByIpAddressWithPage(ipAddress, page);
    }
    
    /**
     * 根据状态码分页查询
     * @param statusCode 状态码
     * @param page 分页参数
     * @return 访问日志分页列表
     */
    @Transactional(readOnly = true)
    public IPage<AccessLog> getLogsByStatusCode(Integer statusCode, Page<AccessLog> page) {
        if (statusCode == null) {
            return new Page<>();
        }
        return baseMapper.findByStatusCodeWithPage(statusCode, page);
    }
    
    /**
     * 根据访问时间范围查询
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @param page 分页参数
     * @return 访问日志分页列表
     */
    @Transactional(readOnly = true)
    public IPage<AccessLog> getLogsByAccessTimeBetween(LocalDateTime startTime, LocalDateTime endTime, Page<AccessLog> page) {
        if (startTime == null || endTime == null) {
            return new Page<>();
        }
        return baseMapper.findByAccessTimeBetween(startTime, endTime, page);
    }
    
    /**
     * 根据响应时间范围查询
     * @param minResponseTime 最小响应时间
     * @param maxResponseTime 最大响应时间
     * @param page 分页参数
     * @return 访问日志分页列表
     */
    @Transactional(readOnly = true)
    public IPage<AccessLog> getLogsByResponseTimeBetween(Long minResponseTime, Long maxResponseTime, Page<AccessLog> page) {
        if (minResponseTime == null || maxResponseTime == null) {
            return new Page<>();
        }
        return baseMapper.findByResponseTimeBetween(minResponseTime, maxResponseTime, page);
    }
    
    /**
     * 统计访问次数
     * @param userId 用户ID（null表示所有用户）
     * @param path 访问路径（null表示所有路径）
     * @param method 请求方法（null表示所有方法）
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 访问次数
     */
    @Transactional(readOnly = true)
    public Long countAccess(Long userId, String path, String method, LocalDateTime startTime, LocalDateTime endTime) {
        return baseMapper.countAccess(userId, path, method, startTime, endTime);
    }
    
    /**
     * 根据条件查询访问日志
     * @param userId 用户ID
     * @param path 访问路径
     * @param method 请求方法
     * @param ipAddress IP地址
     * @param statusCode 状态码
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @param page 页码
     * @param size 每页大小
     * @return 访问日志分页列表
     */
    @Transactional(readOnly = true)
    public IPage<AccessLog> getLogsByConditions(Long userId, String path, String method, String ipAddress, 
                                               Integer statusCode, LocalDateTime startTime, LocalDateTime endTime, 
                                               int page, int size) {
        Page<AccessLog> pageParam = new Page<>(page, size);
        if (startTime != null && endTime != null) {
            return baseMapper.findByAccessTimeBetween(startTime, endTime, pageParam);
        }
        if (userId != null) {
            return getLogsByUserId(userId, pageParam);
        }
        if (StringUtils.hasText(path)) {
            return getLogsByPath(path, pageParam);
        }
        if (StringUtils.hasText(method)) {
            return getLogsByMethod(method, pageParam);
        }
        if (StringUtils.hasText(ipAddress)) {
            return getLogsByIpAddress(ipAddress, pageParam);
        }
        if (statusCode != null) {
            return getLogsByStatusCode(statusCode, pageParam);
        }
        return baseMapper.selectPage(pageParam, null);
    }
    
    /**
     * 统计错误日志（4xx和5xx状态码）
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 错误日志列表
     */
    @Transactional(readOnly = true)
    public List<AccessLog> getErrorLogs(LocalDateTime startTime, LocalDateTime endTime) {
        Page<AccessLog> page = new Page<>(1, Integer.MAX_VALUE);
        IPage<AccessLog> result = baseMapper.findErrorLogsByTimeBetween(startTime, endTime, page);
        return result.getRecords();
    }
    
    /**
     * 分页查询错误日志（4xx和5xx状态码）
     * @param page 分页参数
     * @return 错误日志分页列表
     */
    @Transactional(readOnly = true)
    public IPage<AccessLog> getErrorLogs(Page<AccessLog> page) {
        QueryWrapper<AccessLog> wrapper = new QueryWrapper<>();
        wrapper.and(w -> w.ge("status_code", 400).or().ge("status_code", 500));
        wrapper.orderByDesc("access_time");
        return baseMapper.selectPage(page, wrapper);
    }
    
    /**
     * 获取最近的访问日志
     * @param limit 限制数量
     * @return 最近的访问日志列表
     */
    @Transactional(readOnly = true)
    public List<AccessLog> getRecentLogs(Integer limit) {
        if (limit == null || limit <= 0) {
            limit = 10;
        }
        return baseMapper.findRecentLogs(limit);
    }
    
    /**
     * 统计各路径的访问次数
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 路径访问统计
     */
    @Transactional(readOnly = true)
    public List<Map<String, Object>> countByPath(LocalDateTime startTime, LocalDateTime endTime) {
        return new ArrayList<>();
    }
    
    /**
     * 统计各IP地址的访问次数
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return IP访问统计
     */
    @Transactional(readOnly = true)
    public List<Map<String, Object>> countByIpAddress(LocalDateTime startTime, LocalDateTime endTime) {
        return new ArrayList<>();
    }
    
    /**
     * 统计各状态码的数量
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 状态码统计
     */
    @Transactional(readOnly = true)
    public List<Map<String, Object>> countByStatusCode(LocalDateTime startTime, LocalDateTime endTime) {
        return new ArrayList<>();
    }
    
    /**
     * 统计各用户的访问次数
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 用户访问统计
     */
    @Transactional(readOnly = true)
    public List<Map<String, Object>> countByUserId(LocalDateTime startTime, LocalDateTime endTime) {
        return new ArrayList<>();
    }
    
    /**
     * 计算平均响应时间
     * @param path 访问路径（null表示所有路径）
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 平均响应时间（毫秒）
     */
    @Transactional(readOnly = true)
    public Double getAverageResponseTime(String path, LocalDateTime startTime, LocalDateTime endTime) {
        return 0.0;
    }
    
    /**
     * 统计独立访客数（根据IP地址）
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 独立访客数
     */
    @Transactional(readOnly = true)
    public Long countUniqueVisitors(LocalDateTime startTime, LocalDateTime endTime) {
        return 0L;
    }
    
    /**
     * 获取热门访问路径
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @param limit 限制数量
     * @return 热门路径列表
     */
    @Transactional(readOnly = true)
    public List<Map<String, Object>> getPopularPaths(LocalDateTime startTime, LocalDateTime endTime, Integer limit) {
        if (limit == null || limit <= 0) {
            limit = 10;
        }
        return new ArrayList<>();
    }
    
    /**
     * 获取活跃用户列表
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @param limit 限制数量
     * @return 活跃用户列表
     */
    @Transactional(readOnly = true)
    public List<Map<String, Object>> getActiveUsers(LocalDateTime startTime, LocalDateTime endTime, Integer limit) {
        if (limit == null || limit <= 0) {
            limit = 10;
        }
        return new ArrayList<>();
    }
    
    /**
     * 清理过期日志
     * @param beforeTime 清理此时间之前的日志
     * @return 清理的日志数量
     */
    public int cleanupOldLogs(LocalDateTime beforeTime) {
        if (beforeTime == null) {
            return 0;
        }
        int count = baseMapper.deleteByAccessTimeBefore(beforeTime);
        log.info("Cleaned up {} old access logs before {}", count, beforeTime);
        return count;
    }
    
    /**
     * 记录GET请求访问
     * @param userId 用户ID
     * @param path 访问路径
     * @param ipAddress IP地址
     * @param userAgent 用户代理
     * @param referer 来源页面
     * @param statusCode 状态码
     * @param responseTime 响应时间
     * @return 创建的访问日志
     */
    public AccessLog logGetAccess(Long userId, String path, String ipAddress, String userAgent, String referer, Integer statusCode, Long responseTime) {
        return logAccess(userId, path, "GET", ipAddress, userAgent, referer, statusCode, responseTime, null);
    }
    
    /**
     * 记录POST请求访问
     * @param userId 用户ID
     * @param path 访问路径
     * @param ipAddress IP地址
     * @param userAgent 用户代理
     * @param referer 来源页面
     * @param statusCode 状态码
     * @param responseTime 响应时间
     * @param requestParams 请求参数
     * @return 创建的访问日志
     */
    public AccessLog logPostAccess(Long userId, String path, String ipAddress, String userAgent, String referer, Integer statusCode, Long responseTime, String requestParams) {
        return logAccess(userId, path, "POST", ipAddress, userAgent, referer, statusCode, responseTime, requestParams);
    }
    
    /**
     * 记录PUT请求访问
     * @param userId 用户ID
     * @param path 访问路径
     * @param ipAddress IP地址
     * @param userAgent 用户代理
     * @param referer 来源页面
     * @param statusCode 状态码
     * @param responseTime 响应时间
     * @param requestParams 请求参数
     * @return 创建的访问日志
     */
    public AccessLog logPutAccess(Long userId, String path, String ipAddress, String userAgent, String referer, Integer statusCode, Long responseTime, String requestParams) {
        return logAccess(userId, path, "PUT", ipAddress, userAgent, referer, statusCode, responseTime, requestParams);
    }
    
    /**
     * 记录DELETE请求访问
     * @param userId 用户ID
     * @param path 访问路径
     * @param ipAddress IP地址
     * @param userAgent 用户代理
     * @param referer 来源页面
     * @param statusCode 状态码
     * @param responseTime 响应时间
     * @return 创建的访问日志
     */
    public AccessLog logDeleteAccess(Long userId, String path, String ipAddress, String userAgent, String referer, Integer statusCode, Long responseTime) {
        return logAccess(userId, path, "DELETE", ipAddress, userAgent, referer, statusCode, responseTime, null);
    }
    
    /**
     * 获取系统访问统计概览
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 访问统计概览
     */
    @Transactional(readOnly = true)
    public Map<String, Object> getAccessStatistics(LocalDateTime startTime, LocalDateTime endTime) {
        return Map.of(
            "totalAccess", countAccess(null, null, null, startTime, endTime),
            "uniqueVisitors", countUniqueVisitors(startTime, endTime),
            "averageResponseTime", getAverageResponseTime(null, startTime, endTime),
            "errorCount", getErrorLogs(startTime, endTime).size(),
            "popularPaths", getPopularPaths(startTime, endTime, 5),
            "activeUsers", getActiveUsers(startTime, endTime, 5)
        );
    }
}

